//
// Transactions.h
// libprotea
// Tools Library for the Protea Project / Business Transaction functionality
// Copyright (C) 2003, 2004, 2005 eXegeSys, Inc.
// Copyright (C) 2008 Bruce A. James
//
// This program is part of the Protea Project.
//
// The Protea Project is free software; you can redistribute it and/or modify it 
// under the terms of the GNU General Public License as published by the 
// Free Software Foundation, either version 3 of the License, or (at your 
// option) any later version.
//
// The Protea Project is distributed in the hope that it will be useful, but 
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
// for more details.
// 
// You should have received a copy of the GNU General Public License along 
// with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// Please send correspondence to:
// 
// theproteaproject@gmail.com
//

#ifndef __PROTEA_TRANSACTIONS_H__
#define __PROTEA_TRANSACTIONS_H__

// Forward declaration
class XCTxn;
class XCBuffer;
class XCSQLGen;

// Phased transaction types
#define PHASE_REVIEW 0
#define PHASE_UPDATE 1

// Number of seconds before cleanup
#define XCStatedTxnDelta 300

/// Contains the resources of a stated transaction
class __EXPORT XCStatedTxn : public XCBase {
public:
	/**
		\brief Constructor
		\param txnid Transaction ID
		\param list Collection of buffers to store
		\param app Pointer to the application interface
	*/
	XCStatedTxn( long txnid, XCBufferList* list, XCAppInterface* app );

	/**
		\brief Destructor
	*/
	~XCStatedTxn();

	/**
		\brief Reset timer for this transaction

		Transactions will time out after a specified time interval.  This function resets
		the time interval for this stated transaction.
	*/
	void Reset();

	/** 
		\brief Get the current transaction id
	*/
	long GetId() { return id; };

	// What is this?
	bool active;

	/// Buffers associated with the stated transaction
	XCBufferList* buflist;

	// Undocumented variables, used internally
	XCStatedTxn* next;
	XCAppInterface* App;
	long starttime;

private:
	long id;
};


/// Contains a list of stated transactions
class __EXPORT XCStatedTxnList : public XCBase {
public:
	/**
		\brief Constructor
	*/
	XCStatedTxnList() { list = NULL; };

	/**
		\brief Destructor
	*/
	~XCStatedTxnList(); 

	/** Adds buffers to a stated transaction
		\param txnid Transaction ID
		\param count Number of buffers
		\param ... XCBuffer* pointers
		Accepts any number of buffers (pointers) to store in the list
	*/
	XCStatedTxn* Add( long txnid, long count, ... );

	/**
		\brief Remove a stated transaction from the collection
		\param txnid Transaction ID

		This will remove all information for the specified transaction id.  All buffers
		currently stored with the stated transaction will be freed.

		Note that this function may be called by the system when a stated transaction
		expires.
	*/
	void Remove( long txnid );

	/**
		\brief Find a transaction from the list
		\param txnid Transaction ID

		Returns a pointer to the XCStatedTxn* object
	*/
	XCStatedTxn* Find( long txnid );

	XCAppInterface* App;

	void Cleanup();

private:
	XCStatedTxn* list;
	XCCriticalSection cs;
};




class __EXPORT XCBufferPtr : public XCBase {
public:
	XCBuffer* buffer;
	XCBufferPtr* next;
};

/**
	\brief Collection of buffers

	Contains a collection of buffers for use in user-exit calls.

	NOTE: This list maintains a pointer to the data.  It does not copy and it does NOT
	cleanup the buffer object.
*/
class __EXPORT XCBufferList : public XCBase {
public:
	/**
		\brief Constructor
	*/
	XCBufferList();

	/**
		\brief Destructor
	*/
	~XCBufferList();

	/**
		\brief Add a buffer to the collection
		\param buffer Pointer to the buffer to store in the collection
	*/
	void Add( XCBuffer* buffer );

	/**
		\brief Add many buffers to the collection
		\param count Number of buffer objects passed
		\param ... List of XCBuffer* objects
	*/
	void Add( int count, ... );

	/**
		\brief Remove a buffer from the list, based on the specified index
		\param index Index number of buffer to remove
		Returns a pointer to the buffer that was removed from the collection.
	*/
	XCBuffer* Remove( int index );

	/**
		\brief Remove a buffer from the list, given an XCBuffer pointer
		\param buffer Pointer to the buffer to remove
		If the pointer doesn't match an existing item in the collection, nothing is done.
	*/
	void Remove( XCBuffer* buffer );

	/**
		\brief Clear the buffer collection
	*/
	void Clear();

	/**
		\brief Number of buffers in the collection
	*/
	int buffercount;

	/**
		\brief Returns a buffer from the collection
		\param index of the buffer to return
		If the supplied index is in the range of the collection, a pointer to the
		buffer will be returned.  Otherwise, NULL will be returned.
	*/
	XCBuffer* GetBuffer( int index );

private:
	XCBufferPtr* list_head;
	XCBufferPtr* list_tail;
};




struct XCErrInfo {
	bool sent;
	error_severity severity;
	XCToolsError* error;
	XCErrInfo* next;
};


/**
	\brief Stores application errors, and sends them back to the user.

	This class stores a collection of errors.  
	
	As application errors occur, they are submitted to the collection for storage until
	the end of the transaction.  Depending on the severity of the error added, the collection
	class may trigger an exception, causing the transaction to exit.
*/
class __EXPORT XCAppErrorHandler : public XCBase {
public:

	/**
		\brief Constructor
		\param owner Pointer to an application interface
		\param intrans Pointer to a transaction info interface
	*/
	XCAppErrorHandler( XCAppInterface* owner, XCTransactionInfo* intrans, XCTransactionInfo* abort_check );
	~XCAppErrorHandler();

	/**
		\brief Add an error to the collection
		\param errnum Error number
		\param severity Severity of the error
		\param field Field number in error
		\param parmcount Number of additional parameters supplied
		\param ... Additional parameters
	*/
	void Add( long errnum, error_severity severity=SEV_ERROR, long field=0, long parmcount = 0, ... );

	/**
		\brief Add an error object to the collection
		\param error Error object
	*/
	void Add( XCToolsError& error );

	/**
		\brief Checks for errors in the collection that are failures

		Examines the error collection and errors out if any SEV_ERROR level messages.  If
		any are found, will trigger an exception and cause the transaction to exit.
	*/
	bool Check();

	/**
		\brief Flushes the collection

		Creates transaction result messages for each of the error records currently
		stored in the collection, and clears the collection.  This includes all error
		messages, warnings, and status messages
	*/
	bool Finish();

	/**
		\brief Clears out the list of errors
	*/
	void Clear();

	/**
		\brief Returns the number of error records currently stored in the collection
	*/
	long Count();

	/**
		\brief Increments the buffercount
	*/
	void NextBuffer() { buffercount++; };

private:
	void CheckAbort();
	void SendErrorMessage( XCErrInfo* error );

	XCAppInterface* myowner;
	XCErrInfo* errlist;
	XCTransactionInfo* trans;
	XCTransactionInfo* error_check_trans;

	long buffercount;
};



/// Contains all transaction information
class __EXPORT XCTransactionVars : public XCBase {
public:
	XCTransactionVars( XCAppInterface* app, XCTransactionInfo* transaction, bool requires_header );
	~XCTransactionVars();

	XCTransactionInfo* ReturnResult();

	/// Query object
	XCSQLGen* query;

	/// Result to send back to host
	XCTransactionInfo* result;

	/// Header buffer
	XCBuffer* buffer;

	/// Array of detail buffers
	XCBuffer** detail;

	/// Number of detail buffers
	long detailcount;

	/// Transaction error handler
	XCAppErrorHandler* Errors;

	/// User credentials
	XCCredentials* credentials;

	/// Database transaction
	XCTxn* dbtxn;

	/// Application interface
	XCAppInterface* myapp;

	/// Current phase
	int phase;

	/// Transaction ID
	long id;

protected:
	bool cleanresult;
};




class XCMessageList {
public:
	XCMessageList( XCToolsMessage* my_msg ) { msg = my_msg; sent = false; };
	~XCMessageList();

	void Send( XCTransactionInfo* info );

	XCToolsMessage* msg;
	XCMessageList* next;

private:
	bool sent;
};



class __EXPORT XCTransactionInfo : public XCBase {
public:
	friend class XCMessageList;
	friend class XCAppInterface;

	XCTransactionInfo( XCAppInterface* my_owner, XCMsgPort* port );
	~XCTransactionInfo();

	void AddMessage( XCToolsMessage* new_message, trans_data_type type );
	void AddHeader( XCToolsMessage* trans, trans_data_type type );
	XCToolsMessage* GetHeader() { return header; };

	void SetSuccess( bool new_success = true );
	bool GetSuccess() { return success; };

	bool GetGCSTrans() { return gcs_trans; };
	void SetGCSTrans( bool new_value ) { gcs_trans = new_value; };

	void SetSession( int new_session_id ) { session_id = new_session_id; };
	int GetSession() { return session_id; };

	void SetSuperTrans( superlist* new_super ) {
		if (new_super) {
			supertrans = new_super->trans;
			supertransnum = new_super->id;
		} else {
			supertrans = NULL;
			supertransnum = 0;
		};
	};
	XCTxn* GetSuperTrans() { return supertrans; };

	void SetTransID( long tid ) { transid = tid; };
	long GetTransID() { return transid; };

	void SetTransNumber( long tnbr ) { trans_number = tnbr; };
	long GetTransNumber() { return trans_number; };

	XCMessageList* GetFirstMessage() { return msglist; };

	void SetTotalCount( long tc ) { totalcount = tc; };
	long GetTotalCount() { return totalcount; };

	void SetCount( long cnt ) { count = cnt; };
	long GetCount() { return count; };

	void SetUser( const char* value );
	char* GetUser() { return user; };

	void SetPass( const char* value, char xor_value );
	void SetEncodedPass( const char* value );

	char* GetPass( char* password_buffer, char xor_value );
	char* GetEncodedPass();

	void SetSuperID( long sid ) {
		supertransnum = sid;
		if (sid)
			supertrans = owner->GetSuper( sid );
		else
			supertrans = NULL;
	};

	long GetSuperID() { return supertransnum; };

	void SetAction( char action ) { my_action = action; };
	char GetAction() { return my_action; };

	void SetPhase( char phase ) { my_phase = phase; };
	char GetPhase() { return my_phase; };

	void SetLang( const long value ) { lang = value; };
	long GetLang() { return lang; };

	long GetApplNumber();

	long GetMessageCount() { return message_count; };

	void SetReturnInfo( XCTransactionInfo* msg );
	void SetReturnInfo( XCMsgPort* dest, XCToolsMessage* msg );

	void SetInputInfo( XCMsgPort* from );

	void SetJob();
	bool GetJob();

	bool IsQuery();
	void SetQuery();

	void Release();

	XCTransactionInfo* next;

	XCAppInterface* GetOwner() { return owner; };

	XCMsgPort* GetSource() { return source; };

	XCCredentials*		credentials;	// User credentials

	bool BuffersSent() { return buffers_sent; };

	long GetRecordCount() { return record_count; };
	void SetRecordCount( long new_record_count ) { record_count = new_record_count; };

	long GetStartRecord() { return start_record; };
	void SetStartRecord( long new_start_record ) { start_record = new_start_record; };

	bool GetAbort() { return abort; };

protected:
	bool				in_use;
	int					session_id;
	bool				gcs_trans;
	bool				query_flag;
	bool				job_flag;
	long				transid;		// Transaction ID
	long				trans_number;	// Transaction number
	bool				success;		// Success/failure flag
	bool				abort;			// Abort flag
	XCMsgPort*			source;			// Originator of the transaction
	XCTxn*				supertrans;		// Supertransaction pointer
	long				supertransnum;	// Supertransaction number
	long				totalcount;		// Total number of expected messages
	long				count;			// Message count
	long				lang;			// Language
	XCMessageList*		msglist;		// Linked list of messages
	XCMessageList*		lastmsg;		// Last message in the list
	char*				user;			// User Name
	char*				pass;			// Password
	char				my_action;		// Transaction action (super)
	char				my_phase;		// Transaction phase (0=none,1+)

	long				start_record;	// Record to start on
	long				record_count;	// Record count

	XCToolsMessage*		header;			// Header record
	XCAppInterface*		owner;

	// For return transactions
	XCMsgPort*			dest_port;
	XCToolsMessage*		reply;
	bool				has_header;
	bool				buffers_sent;
	long				message_count;	// Total number of messages sent
};

#endif
